test

9.1 JRA进化

想JRA一样,JFR中也包含了两大部分,分别是内建于JRockit JVM的记录引擎和内建于JRockit Mission Control客户端的分析记录分析工具。记录引擎用于生成可供分析工具处理的记录文件,分析文件时,并不要求必须有活动连接,其本身是自描述的,即文件本身就包含了所有相关的元数据。此外,该文件也可以被发送给其他第3方分析工具做进一步的详细分析。

在本章中,JFR和JFA表示同一个意思,可以互换使用。

在JFR中,记录文件不再使用XML格式,所有内容均记录在内存缓冲区中,并辅以相应的时间戳,并在合适的时机将之写入到构成记录的二进制文件中,此外,还通过专门的Java API实现了自定义事件和自定义用户分析接口的功能。

第8章中曾经提到过,JRA的记录是以XML格式存储的,其记录文件的后缀名为.jra。而在JFR中,文件后缀名变成了.jfr,存储格式也改成了二进制格式。由于可能会产生大量的目标事件,因此需要避免不必要的开销,将数据压缩存储。JRA记录无法向前兼容,JFR也无法打开JRA的记录文件。

9.1.1 关于事件

正如前面介绍的,在JFR中,事件就是在某个具体的时间点记录下的数据。

其中,事件包含一下种类型:

  • 持续事件(duration event): 指包含了起始时间和截止时间的事件,例如 Garbage Collection事件。
  • 计时事件(timed event): 指可以设置持续时间阈值的持续事件,例如 Java Wait事件和 Java Sleep事件。
  • 立即事件(instant event): 指事件不会持续,记录的内容也只有开始时间,例如 ExceptionEvent Settings Changed异常设置变更事件。
  • 可请求事件(requestable event): 指可以被配置为周期性轮询记录引擎的事件。该事件是通过在记录引擎中使用一个单独的线程来定时调用指定方法实现的,例如 CPU Load Sample事件。

JFR中记录的事件由记录生成器产生,记录生成器定义了事件的具体类型。事件类型中包含了用于描述该类型本身信息的元数据。这些元数据中包含了该事件本身所包含的属性信息、属性的类型信息和属性的具体描述信息。JFR的记录文件中都包含了对该事件生成器的描述信息。

JRockit JVM作为其中一种事件生成器,优势巨大,它可以以较小的运行时代价,很方便的记录下运行时需要收集的事件信息。此外,用户可以通过调用相关的Java API,在JRockit JVM创建的底层事件上附加额外的上下文属性。

9.1.2 记录引擎

记录引擎(recording engine,有时也称为记录代理),内建于JVM之中,针对事件生成做了大量优化以完成相关任务,这些任务其中包括:

  • 记录工具(recording facility): 记录引擎的主要用途肯定是记录应用程序运行过程中所发生的事件。为了高效完成记录任务,其内部使用了线程局部缓冲(Thread Local Buffer),当发生事件时就将其记录到局部缓冲中,若线程局部缓冲已满,就记录到全局缓冲区(global buffer)中。如果全局缓冲区也满了,则根据配置选项来决定,是以二进制格式将全局缓冲区中的内容写入到硬盘中,还是循环重用之前的区域。
  • 追踪调用栈(stack trace): 预先配置相关选项后,JFR会在记录相关事件时,顺带记录下调用栈信息。在查找事件发生源时,这些信息将非常有用。
  • 设置阈值(threshold): 设置相应的阈值后,JFR只会记录执行时间超过该阈值的事件,这样就可以过滤掉一部分事件,防止产生过多记录。每种事件类型都可以设置各自的阈值。
  • 附带时间戳: 正如在第5章介绍的,使用System.currentTimeMillis()方法获取系统时间的具有不小的执行开销。因此,记录引擎为记录时间戳而提供了一个高度优化的本地时间版本。

Figure 9-1

由于JRockit R28是作为补丁版本发布的,因此若是默认开启事件记录可能会带来一些麻烦。故而决定在启动JVM时,并不会立即启动记录引擎。其实在设计之初,记录引擎和JRockit JVM事件发生源就是放在一起考虑的,在开发测试过程中,也都是放在一起的(即便是做压力测试时,也不例外)。在将来的JRockit版本中,可能会对记录引擎做一些改动。

对于正在执行的事件记录而言,都会有一个ID和名字,其中ID具有唯一性。记录ID会在创建记录时设置,用于标识当前的记录。例如,可以在JRCMD中,通过记录ID来引用某个事件记录。

在启动JRockit时,附加以下命令行参数,即可启用JFR事件记录:

-XX:FlightRecorderOptions=defaultrecording=true

使用上面的命令行参数,可以创建一个ID为0,名字为JRockit default的事件记录。

JFR中可以同时存在多个事件记录。如果同时有多个事件记录处于 活跃(live)状态,则在记录的时候,会将各自的事件类型进行聚合,并根据预设的阈值进行过滤。对于刚刚接触JFR的用户来说,这可能会带来一些困扰,而实际上,确实有可能出现记录的事件比期望的多的情况。

通过修改默认记录的事件设置选项(event settings)可以对记录引擎做详细配置,或者使用不同的配置开启一个新的记录。如果想要过滤掉多余的记录信息,请修改相关配置。

9.1.3 启动参数

有多种方式可用于对记录引擎的方方面面进行配置,不过其中的某些方式只能在以命令行启动JVM时使用。

有两个主要的命令行参数用于对JFR进行配置。其一是用于控制是否开启JFR的命令行参数:

-XX:[+|-]FlightRecorder

其二是用于控制JFR运行行为:

-XX:FlightRecorderOptions=parameter1=value1[,parameter2=value2]

可用参数如下:

Parameter                    Description
settings=[name|filepath]     在服务器端载入额外的配置模板。默认情况下,配置模板存在于 **JROCKIT_HOME/jre/lib/jfr**路径下。
repository=[dir]             JFR记录数据的路径,可看作是JFR的临时目录。默认情况下,存放于java.io.tmpdir属性定义的目录下,子目录的名字格式为 **yyyy_mm_dd_hh_mm_ss_pid**。例如,若进程号为4711,则创建的临时目录的名字为 **2010_04_21_16_28_59_4711**。
threadbuffersize=[size]      指定线程局部缓冲区(Thread Local Buffer)的大小,默认值为5KB。
globalbuffersize=[size]      指定全局局部缓冲区(Global Local Buffer)的大小,默认值为64KB。
numglobalbuffers=[num]       指定全局局部缓冲区(Global Local Buffer)的数量,默认值为8。
maxchunksize=[size]          指定存储的单个数据块的大小,默认值为12MB。
continuous=[true|false]      指定是否启用默认的连续记录,即使用记录ID0进行连续记录。无论该值设置为true还是false,只要启用了JFR,都可以通过JRockit Mission Control来开启连续记录。正如前文提到了,在JRockit R28中,禁用了默认记录,不过在将来的版本中可能会将之开启。
disk=[true|false]            指定是否将数据记录到硬盘中。默认为false,即会循环使用内存空间的记录区域。通过JRockit Mission Control或JRCMD,可以手动将记录内容刷入到硬盘中。
maxage=[nanotime]            指定数据在硬盘上保留的最长时间,单位为纳秒,默认值为0,即保留所有数据。
maxsize=[size]               指定最大保留多少数据,默认值为0,即保留所有数据。

无论是使用JRCMD还是命令参数,指定的参数选项都会通过模板文件以JSON格式被记录下来。JRockit发行版中附带了几个实例模板,位于JROCKIT_HOME/jre/lib/jfr目录下。这些模板就是所谓的服务器端模板(server-side templates),因所使用的JRockit Mission Control客户端不同而有所区别。基于这些模板,用户可以根据实际需要开发定制话的模板。

有关服务器端模板的详细内容超出了本书的范畴,这里不再赘述。在第11章中将会在如何使用JRCMD来控制记录的生命周期。

9.1.3.1 开启基于时间的记录

与JRA类似,JFR也可以通过命令行参数来开启有时间限制的记录。在JFR中,命令行参数-XX:StartFlightRecording可用于对执行时间做相关设置,例如,可以推迟记录的执行时间以便可以跳过JVM的阶段。下面的示例中,JFR会在JVM启动2分钟后再开始记录,记录持续一分钟,记录名为 MyRecording,并将结果存储到 c:\tmp\myrecording.jfr中。当然,这里也可以使用服务器端模板,通过名字引用即可,在示例中使用模板文件的是 profile.jfs

-XX:StartFlightRecording=delay=120s,duration=60s,name=MyRecording,filename=C:\tmp\myrecording.jfr,settings=profile

更多有关命令行参数StartFlightRecording选项的内容,请参见JRockitR2的相关手册。

本章的剩余部分将着重介绍如何通过JRockit Mission Control客户端来控制JFR。